<?php
/**
 * Logger.php
 *
 * 系统日志处理类, 单例模式.
 *
 * This source file is subject to the new BSD license that is bundled
 * with this package in the file LICENSE.txt.
 * It is also available through the world-wide-web at this URL:
 * http://momoger.com/license
 *
 * @category	App
 * @package 	App_System
 * @author 		Guya
 * @version    	1.0
 * @copyright  	Copyright © 2009 www.momoger.com All Rights Reserved.
 * @license    	http://momoger.com/license     New BSD License
 */

/**
 * 系统日志处理类, 单例模式.
 *
 * @category	App
 * @package 	App_System
 * @copyright  	Copyright © 2009 www.momoger.com All Rights Reserved.
 * @license    	http://momoger.com/license     New BSD License
 */
class App_System_Logger {

	/**
	 * 系统日志静态变量
	 *
	 * @var App_System_Logger
	 */
	protected static $instance = null;

	/**
	 * 日志记录器
	 *
	 * @var Zend_Log
	 */
	protected $logger = null;

	/**
	 * 构造函数。 不允许直接初始化。
	 *
	 */
	protected function __construct() {
		//get the loger setting
		$logConfig = Zend_Registry::get(APP_CONFIG);

		//Application config allow log
		if (isset($logConfig['log']['enabled']) && $logConfig['log']['enabled']) {

			//start a Zend Logger
			$this->logger = new Zend_Log();

			//add the process information
			$this->logger->setEventItem('pid', getmypid());

			//add the client request ip address information
			$this->logger->setEventItem('clientIp', $this->getClientIp());

			//use file save log
			if (isset($logConfig['log']['writer']['file']['enabled']) && $logConfig['log']['writer']['file']['enabled']) {
				//open log file by day
				$stream = @fopen($logConfig['log']['writer']['file']['path'] . '/' . $logConfig['log']['host'] . '-' . date('Y-m-d') . '-logger.log', 'a', false);
				if (!$stream) {
					//throw new Exception('Failed open log file!');
					echo 'Failed open log file!';
				} else {
					//create stream writer
					$writerStream = new Zend_Log_Writer_Stream($stream);

					//format the log write context
					$format = '[%priorityName%:%priority%][PID:%pid%][IP:%clientIp%]' . PHP_EOL . '%message%' . PHP_EOL . '%timestamp%' . PHP_EOL . PHP_EOL;
					$formatter = new Zend_Log_Formatter_Simple($format);

					//XML formatter
					//$formatter = new Zend_Log_Formatter_Xml();
					//$formatter = new Zend_Log_Formatter_Xml('appLog', array('msg' => 'message', 'type' => 'priorityName', 'level'=>'priority', 'clientIp'=>'clientIp', 'PID'=>'pid', 'time'=>'timestamp'));

					//active the formater
					$writerStream->setFormatter($formatter);

					//add loger write
					$this->logger->addWriter($writerStream);
				}
			}

			//use database save log
			if (isset($logConfig['log']['writer']['db']['enabled']) && $logConfig['log']['writer']['db']['enabled']) {

				/**
				 * Example table construct
				 * DROP TABLE IF EXISTS `200907_{host}_logs`;
				 * CREATE TABLE IF NOT EXISTS `200907_logs` (
				 *  `logID` int(10) unsigned NOT NULL auto_increment COMMENT '主键ID,自动流水号',
				 *  `logType` tinyint(3) unsigned default '99' COMMENT '日志等级',
				 *  `logPid` int(10) unsigned default '0' COMMENT '日志PID',
				 *  `logName` varchar(20) default 'DEBUG' COMMENT '日志名称',
				 *  `logIp` varchar(30) default '127.0.0.1' COMMENT '驱动创建日志客户端IP',
				 *  `logTime` varchar(30) default '' COMMENT '日志创建时间',
				 *  `logMsg` text COMMENT '日志内容',
				 *  PRIMARY KEY  (`logID`)
				 * ) ENGINE=MyISAM DEFAULT CHARSET=utf8 COMMENT='系统日志保存表,每月使用一张新表.' AUTO_INCREMENT=1 ;
				 */

				//set log field and table field mapping.
				$columnMapping = array(
					'logType' => 'priority',
					'logPid' => 'pid',
					'logName' => 'priorityName',
					'logIp' => 'clientIp',
					'logTime' => 'timestamp',
					'logMsg' => 'message'
				);

				//get db adapter
				$logDbAdapter = Zend_Db::factory($logConfig['log']['writer']['db']['adapter'], $logConfig['log']['writer']['db']['params']);

				//create database writer
				$writerDb = new Zend_Log_Writer_Db($logDbAdapter, date('Ym') . '_' . $logConfig['log']['host'] . '_logs', $columnMapping);

				//add loger write
				$this->logger->addWriter($writerDb);
			}

			//create log filter
			if (isset($logConfig['log']['level'])) {
				//log level stopping
				$filterLevel = new Zend_Log_Filter_Priority((int)$logConfig['log']['level']);
				$this->logger->addFilter($filterLevel);

				//log ip stopping
				/**
				 * ip rule:
				 * 192 => 192.0.0.0 - 192.255.255.255
				 * 192.168 => 192.168.0.0 - 192.168.255.255
				 * 192.168.1 => 192.168.1.0 - 192.168.1.255
				 * 192.168.1.1 => 192.168.1.1
				 */

				//$filterIp = new Anjuke_Log_Filter_Ip('127.0.0.1');
				//$this->logger->addFilter($filterIp);
			}
		}
	}

	/**
	 * 获取请求端IP地址。
	 *
	 * @return string
	 */
	protected function getClientIp() {
		$realip = NULL;
		if (isset($_SERVER)) {
			if (isset($_SERVER["HTTP_X_FORWARDED_FOR"])) {
				$realip = $_SERVER["HTTP_X_FORWARDED_FOR"];
			} elseif (isset($_SERVER["HTTP_CLIENT_IP"])) {
				$realip = $_SERVER["HTTP_CLIENT_IP"];
			} else {
				$realip = $_SERVER["REMOTE_ADDR"];
			}
		} else {
			if (getenv('HTTP_X_FORWARDED_FOR')) {
				$realip = getenv( 'HTTP_X_FORWARDED_FOR');
			} elseif (getenv('HTTP_CLIENT_IP')) {
				$realip = getenv('HTTP_CLIENT_IP');
			} else {
				$realip = getenv('REMOTE_ADDR');
			}
		}

		return $realip;
	}

	/**
	 * 记录日志接口。
	 *
	 * @param string $msg
	 * @param int $level 日志等级. 可使用 0(emergency),1(alert),2(critical),3(error),4(warning),5(notice),6(information),7(debug)
	 */
	public function log($msg = '', $level = 7) {
		if (!$msg || null === $this->logger) {
			return ;
		}
		$this->logger->log($msg, $level);
	}

	/**
	 * 简写调用日志记录接口. DEBUG 模式日志
	 *
	 * @param string $msg 日志内容.
	 */
	public function debug($msg = '') {
		$this->log($msg, 7);
	}

	/**
	 * 简写调用日志记录接口. INFO 模式日志
	 *
	 * @param string $msg 日志内容.
	 */
	public function info($msg = '') {
		$this->log($msg, 6);
	}

	/**
	 * 简写调用日志记录接口. NOTICE 模式日志
	 *
	 * @param string $msg 日志内容.
	 */
	public function notice($msg = '') {
		$this->log($msg, 5);
	}

	/**
	 * 简写调用日志记录接口. WARN 模式日志
	 *
	 * @param string $msg 日志内容.
	 */
	public function warn($msg = '') {
		$this->log($msg, 4);
	}

	/**
	 * 简写调用日志记录接口. ERR 模式日志
	 *
	 * @param string $msg 日志内容.
	 */
	public function err($msg = '') {
		$this->log($msg, 3);
	}

	/**
	 * 简写调用日志记录接口. CRIT 模式日志
	 *
	 * @param string $msg 日志内容.
	 */
	public function crit($msg = '') {
		$this->log($msg, 2);
	}

	/**
	 * 简写调用日志记录接口. ALERT 模式日志
	 *
	 * @param string $msg 日志内容.
	 */
	public function alert($msg = '') {
		$this->log($msg, 1);
	}

	/**
	 * 简写调用日志记录接口. EMERG 模式日志
	 *
	 * @param string $msg 日志内容.
	 */
	public function emerg($msg = '') {
		$this->log($msg, 0);
	}

	/**
	 * 获取日志对象
	 *
	 * @return App_System_Logger
	 */
	public static function getInstance() {
		if (null === self::$instance) {
            self::$instance = new self();
        }
        return self::$instance;
	}
}